// middleware/jwt.go
package middleware

import (
	"bsm/config"
	"bsm/constants"
	"bsm/logger"
	"bsm/models"
	"bsm/services"
	"fmt"
	"net/http"
	"sort"
	"time"

	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"
)

var (
	jwtMiddleware  *jwt.GinJWTMiddleware
	sessionService services.RedisSessionService
)

func InitAuthMiddleware(authService services.AuthService, sessService services.RedisSessionService) (*jwt.GinJWTMiddleware, error) {
	if authService == nil || sessService == nil {
		return nil, fmt.Errorf("authService and sessionService must not be nil")
	}

	sessionService = sessService

	var err error
	jwtMiddleware, err = jwt.New(&jwt.GinJWTMiddleware{
		SendCookie:        true,
		SendAuthorization: true,
		TokenLookup:       "header: Authorization, query: token, cookie: jwt",
		TokenHeadName:     "Bearer",
		TimeFunc:          time.Now,

		Realm:       "bsm zone",
		Key:         []byte(GetJWTSecret()),
		Timeout:     time.Hour * 24,
		MaxRefresh:  time.Hour * 24,
		IdentityKey: "user_id",

		PayloadFunc: func(data interface{}) jwt.MapClaims {
			if v, ok := data.(*models.UserWithRoles); ok {
				// 提取角色ID列表
				var roleIDs []string
				for _, role := range v.Roles {
					roleIDs = append(roleIDs, role.RoleID)
				}
				isAdmin, _ := authService.CheckUserRole(v.UserID, models.UserRole_Admin)
				var utype = 0
				if isAdmin {
					utype = 1
				}
				claims := jwt.MapClaims{
					"user_id":   v.UserID,
					"user_name": v.UserName,
					"user_type": utype,
					"org_code":  v.OrgCode,
					"org_level": v.OrgLevel,
					"roles":     roleIDs,
				}
				return claims
			}

			logger.WithFields(map[string]interface{}{
				"layer":     "middleware",
				"operation": "InitAuthMiddleware-PayloadFunc",
			}).WithField("data_type", fmt.Sprintf("%T", data)).Error("data类型不正确")
			return jwt.MapClaims{}
		},

		IdentityHandler: func(c *gin.Context) interface{} {
			claims := jwt.ExtractClaims(c)

			if len(claims) == 0 {
				return nil
			}

			// 返回一个只包含基础信息和角色ID的对象
			identity := &models.AuthIdentity{
				UserID:   getStringClaim(claims, "user_id"),
				UserName: getStringClaim(claims, "user_name"),
				UserType: getIntClaim(claims, "user_type"),
				OrgCode:  getStringClaim(claims, "org_code"),
				OrgLevel: getIntClaim(claims, "org_level"),
				RoleIDs:  getStringSliceClaim(claims, "roles"),
			}

			c.Set("user_info", identity)
			return identity
		},

		// 登录认证处理
		Authenticator: func(c *gin.Context) (interface{}, error) {
			var loginVals struct {
				UserID   string `form:"user_id" json:"user_id" binding:"required"`
				Password string `form:"password" json:"password" binding:"required"`
			}

			if err := c.ShouldBind(&loginVals); err != nil {
				logger.WithFields(map[string]interface{}{
					"layer":     "middleware",
					"operation": "InitAuthMiddleware-Authenticator",
				}).WithError(err).Error("参数绑定失败")
				return nil, jwt.ErrMissingLoginValues
			}

			valid, code, userWithRoles := authService.UserLogin(loginVals.UserID, loginVals.Password)
			c.Set("login_code", code)
			if !valid {
				logger.WithFields(map[string]interface{}{
					"layer":         "middleware",
					"operation":     "InitAuthMiddleware-Authenticator",
					"user_id":       loginVals.UserID,
					"error_code":    code,
					"error_message": constants.GetLoginMessage(code),
				}).Warn("登录失败")
				return nil, jwt.ErrFailedAuthentication
			}

			c.Set("user_info", &userWithRoles)

			return &userWithRoles, nil
		},

		// 授权处理
		Authorizator: func(data interface{}, c *gin.Context) bool {
			if user, ok := data.(*models.AuthIdentity); ok {
				c.Set("user_id", user.UserID)
				c.Set("user_name", user.UserName)
				c.Set("user_type", user.UserType)
				c.Set("org_code", user.OrgCode)
				c.Set("org_level", user.OrgLevel)
				c.Set("user_roles", user.RoleIDs)

				token := jwt.GetToken(c)
				if token == "" {
					return false
				}

				// 检查Redis中是否存在对应的会话
				session, err := sessionService.GetSessionByToken(token)
				if err != nil || session == nil {
					logger.WithFields(map[string]interface{}{
						"layer":     "middleware",
						"operation": "InitAuthMiddleware-Authorizator",
						"token":     token,
						"error":     err,
					}).Warn("会话不存在或查询失败")
					return false // 会话不存在，认证失败
				}

				return true
			}
			return false
		},

		Unauthorized: func(c *gin.Context, code int, message string) {
			// 从上下文中获取具体的业务错误码
			loginCode, exists := c.Get("login_code")
			if !exists {
				loginCode = constants.LoginAuthFailed
			}

			c.JSON(http.StatusOK, models.ResponseModel{
				Code: loginCode.(int),
				Msg:  constants.GetLoginMessage(loginCode.(int)), // 使用统一消息
				Data: false,
			})
		},

		LoginResponse: func(c *gin.Context, code int, token string, expire time.Time) {
			if user, exists := c.Get("user_info"); exists {
				userWithRoles, ok := user.(*models.UserWithRoles)
				if !ok {
					logger.Error("类型断言失败")
					c.JSON(http.StatusInternalServerError, models.ResponseModel{
						Code: constants.LoginServerError,
						Msg:  constants.GetLoginMessage(constants.LoginServerError),
					})
					return
				}

				webUser, err := authService.GetWebUser(userWithRoles.ProjectUser)
				if err != nil {
					logger.WithFields(map[string]interface{}{
						"layer":     "middleware",
						"operation": "InitAuthMiddleware-LoginResponse",
						"user_id":   userWithRoles.UserID,
						"error":     err.Error(),
					}).Error("获取用户信息失败")
					c.JSON(http.StatusInternalServerError, models.ResponseModel{
						Code: constants.LoginServerError,
						Msg:  constants.GetLoginMessage(constants.LoginServerError),
					})
					return
				}

				// 处理多点登录逻辑...
				activeCount, err := sessionService.GetActiveSessionsCount(webUser.UserID)
				if err != nil {
					logger.WithFields(map[string]interface{}{
						"layer":     "middleware",
						"operation": "InitAuthMiddleware-LoginResponse",
						"user_id":   webUser.UserID,
						"error":     err.Error(),
					}).Error("获取活跃会话数量失败")
					c.JSON(http.StatusInternalServerError, models.ResponseModel{
						Code: constants.LoginServerError,
						Msg:  constants.GetLoginMessage(constants.LoginServerError),
					})
					return
				}

				maxSessions := 3
				if activeCount >= maxSessions {
					oldestSessions, _ := sessionService.GetUserSessions(webUser.UserID)
					sessionCount := len(oldestSessions)
					logger.WithFields(map[string]interface{}{
						"layer":            "middleware",
						"operation":        "InitAuthMiddleware-LoginResponse",
						"current_sessions": sessionCount,
						"max_sessions":     maxSessions,
						"user_id":          webUser.UserID,
					}).Info("会话数量检查")
					if sessionCount > 0 {
						// 按最后活跃时间排序，踢掉最旧的
						sort.Slice(oldestSessions, func(i, j int) bool {
							return oldestSessions[i].LastActive.Before(oldestSessions[j].LastActive)
						})

						sessionsToRemove := len(oldestSessions) - maxSessions + 1
						if sessionsToRemove > 0 {
							for i := 0; i < sessionsToRemove; i++ {
								sessionService.RemoveSession(oldestSessions[i].SessionID)
							}
						}
					}
				}

				// 创建新会话
				userAgent := c.Request.UserAgent()
				ipAddress := c.ClientIP()
				session, err := sessionService.CreateSession(webUser, token, userAgent, ipAddress)
				if err != nil {
					logger.WithFields(map[string]interface{}{
						"layer":     "middleware",
						"operation": "InitAuthMiddleware-LoginResponse",
						"user_id":   webUser.UserID,
						"username":  webUser.UserName,
						"error":     err.Error(),
					}).Error("创建会话失败")
					c.JSON(http.StatusInternalServerError, models.ResponseModel{
						Code: constants.LoginServerError,
						Msg:  constants.GetLoginMessage(constants.LoginServerError),
					})
					return
				}

				logger.WithFields(map[string]interface{}{
					"layer":      "middleware",
					"operation":  "InitAuthMiddleware-LoginResponse",
					"user_id":    webUser.UserID,
					"username":   webUser.UserName,
					"org_code":   webUser.OrgCode,
					"ip_address": ipAddress,
				}).Info("用户登录成功")

				c.JSON(code, models.ResponseModel{
					Code: 0,
					Msg:  "登录成功，欢迎使用预结算管理平台！",
					Data: gin.H{
						"token":   token,
						"user":    webUser,
						"session": session,
					},
				})
				return
			}

		},
		LogoutResponse: func(c *gin.Context, code int) {
			claims := jwt.ExtractClaims(c)
			if len(claims) > 0 {
				userID, ok1 := claims["user_id"].(string)
				userName, ok2 := claims["user_name"].(string)

				if ok1 && ok2 {
					logger.WithFields(map[string]interface{}{
						"layer":       "middleware",
						"operation":   "InitAuthMiddleware-LogoutResponse",
						"user_id":     userID,
						"user_name":   userName,
						"ip_address":  c.ClientIP(),
						"logout_time": time.Now(),
					}).Info("用户登出成功")

					tokenString := jwt.GetToken(c)
					if tokenString != "" {
						sessionService.RemoveSessionByToken(tokenString)
					}

					c.JSON(code, models.ResponseModel{
						Code: 0,
						Msg:  "登出成功",
						Data: gin.H{
							"user_id":     userID,
							"user_name":   userName,
							"logout_time": time.Now().Format("2006-01-02 15:04:05"),
							"ip":          c.ClientIP(),
						},
					})
					return
				}
			}

			c.JSON(code, models.ResponseModel{
				Code: 0,
				Msg:  "登出成功",
			})
		},
	})
	return jwtMiddleware, err
}

// 获取JWT中间件
func GetAuthMiddleware() *jwt.GinJWTMiddleware {
	return jwtMiddleware
}

// 获取SessionService
func GetSessionService() services.RedisSessionService {
	return sessionService
}

// GetJWTSecret 获取JWT密钥
func GetJWTSecret() []byte {
	secret := config.Get().AppConfig.JWTSecret

	if secret == "your-default-secret-key-change-in-production" {
		logger.WithFields(map[string]interface{}{
			"layer":     "middleware",
			"operation": "InitAuthMiddleware-GetJWTSecret",
		}).Warn("使用默认JWT密钥，生产环境请修改")
	}

	if len(secret) < 32 {
		logger.WithFields(map[string]interface{}{
			"layer":         "middleware",
			"operation":     "InitAuthMiddleware-GetJWTSecret",
			"secret_length": len(secret),
		}).Warn("JWT密钥太短，建议使用至少32字符")
	}

	return []byte(secret)
}

// 辅助函数
func getStringClaim(claims jwt.MapClaims, key string) string {
	if val, exists := claims[key]; exists {
		if str, ok := val.(string); ok {
			return str
		}
	}
	return ""
}

func getIntClaim(claims jwt.MapClaims, key string) int {
	if val, exists := claims[key]; exists {
		if num, ok := val.(float64); ok {
			return int(num)
		}
	}
	return 0
}

func getStringSliceClaim(claims jwt.MapClaims, key string) []string {
	if val, exists := claims[key]; exists {
		switch v := val.(type) {
		case []string:
			return v
		case []interface{}:
			var result []string
			for _, item := range v {
				if str, ok := item.(string); ok {
					result = append(result, str)
				}
			}
			return result
		}
	}
	return []string{}
}

// func getAuthIdentity(c *gin.Context) (*models.AuthIdentity, bool) {
// 	if identity, exists := c.Get("user_info"); exists {
// 		if authIdentity, ok := identity.(*models.AuthIdentity); ok {
// 			return authIdentity, true
// 		}
// 	}
// 	return nil, false
// }

// func getUserWithRoles(c *gin.Context) (*models.UserWithRoles, bool) {
// 	if user, exists := c.Get("user_info"); exists {
// 		if userWithRoles, ok := user.(*models.UserWithRoles); ok {
// 			return userWithRoles, true
// 		}
// 	}
// 	return nil, false
// }
